﻿using System;
using System.Linq;
using CID.Domain.Users;
using CID.Tests.Support;
using CID.Web.Support;
using NailsFramework.UserInterface;
using NUnit.Framework;

namespace CID.Web.Tests.Authorization
{
    abstract class BaseControllerAuthorizationTests : BaseFunctionalTests
    {
        #region Static Members
        private static Type[] Controllers { get; set; }

        static BaseControllerAuthorizationTests()
        {
            Controllers = typeof(CIDAuthorizeAttribute).Assembly.GetTypes().Where(x => typeof(NailsController).IsAssignableFrom(x) && !x.IsAbstract).ToArray();
        }

        private static bool IsControllerAuthorizedForRole(Type controllerType, UserRole role)
        {
            if (!typeof(NailsController).IsAssignableFrom(controllerType) || controllerType.IsAbstract)
                throw new InvalidCastException(String.Format("The {0} is not a valid NailsController", controllerType));
            var authorizeAttributes = controllerType.GetCustomAttributes(typeof(CIDAuthorizeAttribute), true).Cast<CIDAuthorizeAttribute>();
            var result = (authorizeAttributes.Count() == 0);
            foreach (var authorizeAttribute in authorizeAttributes)
                result |= authorizeAttribute.UserRoles.Contains(role);

            return result;
        }
        #endregion

        protected abstract UserRole Role { get; }
        protected abstract Type[] AuthorizedControllers { get; }

        [Test]
        public void TestAuthorizedControllersAccess_AllShouldBeAuthorizedForRole()
        {
            foreach (var controller in AuthorizedControllers)
                Assert.IsTrue(IsControllerAuthorizedForRole(controller, Role), String.Format("The controller {0} should be authorized for {1} role but it's not", controller, Role));
        }

        [Test]
        public void TestNotAuthorizedControllersAccess_NoneShouldBeAuthorizedForRole()
        {
            foreach (var controller in Controllers.Where(x => !AuthorizedControllers.Contains(x)))
                Assert.IsFalse(IsControllerAuthorizedForRole(controller, Role), String.Format("The controller {0} should NOT be authorized for {1} role but it's", controller, Role));
        }
    }
}
